@use 'sass:map';
@use '@material/button/button' as mdc-button;
@use '@material/button/variables' as mdc-button-variables;
@use '@material/button/button-text-theme' as mdc-button-text-theme;
@use '@material/button/button-filled-theme' as mdc-button-filled-theme;
@use '@material/button/button-protected-theme' as mdc-button-protected-theme;
@use '@material/button/button-outlined-theme' as mdc-button-outlined-theme;
@use '@material/typography/typography' as mdc-typography;
@use '@material/theme/custom-properties' as mdc-custom-properties;

@use './button-base';
@use '../core/mdc-helpers/mdc-helpers';
@use '../core/style/private' as style-private;
@use '../core/tokens/token-utils';
@use '../core/focus-indicators/private' as focus-indicators-private;
@use '../core/tokens/m2/mdc/filled-button' as tokens-mdc-filled-button;
@use '../core/tokens/m2/mat/filled-button' as tokens-mat-filled-button;
@use '../core/tokens/m2/mdc/outlined-button' as tokens-mdc-outlined-button;
@use '../core/tokens/m2/mat/outlined-button' as tokens-mat-outlined-button;
@use '../core/tokens/m2/mdc/protected-button' as tokens-mdc-protected-button;
@use '../core/tokens/m2/mat/protected-button' as tokens-mat-protected-button;
@use '../core/tokens/m2/mdc/text-button' as tokens-mdc-text-button;
@use '../core/tokens/m2/mat/text-button' as tokens-mat-text-button;

@include mdc-helpers.disable-mdc-fallback-declarations {
  @include mdc-button.static-styles-without-ripple($query: mdc-helpers.$mdc-base-styles-query);
}

@include mdc-custom-properties.configure($emit-fallback-values: false, $emit-fallback-vars: false) {
  .mat-mdc-button {
    $mdc-text-button-slots: tokens-mdc-text-button.get-token-slots();

    @include mdc-button-text-theme.theme-styles($mdc-text-button-slots);
    @include button-base.mat-private-button-horizontal-layout(tokens-mat-text-button.$prefix,
      tokens-mat-text-button.get-token-slots(), true);
    @include button-base.mat-private-button-ripple(tokens-mat-text-button.$prefix,
      tokens-mat-text-button.get-token-slots());
    @include button-base.mat-private-button-touch-target(false, tokens-mat-text-button.$prefix,
      tokens-mat-text-button.get-token-slots());

    @include token-utils.use-tokens(tokens-mdc-text-button.$prefix, $mdc-text-button-slots) {
      // We need to re-apply the disabled tokens since MDC uses
      // `:disabled` which doesn't apply to anchors.
      @include button-base.mat-private-button-disabled {
        @include token-utils.create-token-slot(color, disabled-label-text-color);
      }
    }
  }

  .mat-mdc-unelevated-button {
    $mdc-filled-button-slots: tokens-mdc-filled-button.get-token-slots();

    @include mdc-button-filled-theme.theme-styles($mdc-filled-button-slots);
    @include button-base.mat-private-button-horizontal-layout(tokens-mat-filled-button.$prefix,
      tokens-mat-filled-button.get-token-slots(), false);
    @include button-base.mat-private-button-ripple(tokens-mat-filled-button.$prefix,
      tokens-mat-filled-button.get-token-slots());
    @include button-base.mat-private-button-touch-target(false, tokens-mat-filled-button.$prefix,
      tokens-mat-filled-button.get-token-slots());

    @include token-utils.use-tokens(tokens-mdc-filled-button.$prefix, $mdc-filled-button-slots) {
      // We need to re-apply the disabled tokens since MDC uses
      // `:disabled` which doesn't apply to anchors.
      @include button-base.mat-private-button-disabled {
        @include token-utils.create-token-slot(color, disabled-label-text-color);
        @include token-utils.create-token-slot(background-color, disabled-container-color);
      }
    }
  }

  .mat-mdc-raised-button {
    $mdc-button-protected-slots: tokens-mdc-protected-button.get-token-slots();

    @include mdc-button-protected-theme.theme-styles(map.merge($mdc-button-protected-slots, (
      // Exclude the elevation tokens here since we output them manually below.
      container-elevation: null,
      hover-container-elevation: null,
      disabled-container-elevation: null,
      focus-container-elevation: null,
      pressed-container-elevation: null,
      container-shadow-color: null,
    )));
    @include button-base.mat-private-button-horizontal-layout(tokens-mat-protected-button.$prefix,
      tokens-mat-protected-button.get-token-slots(), false);
    @include button-base.mat-private-button-ripple(tokens-mat-protected-button.$prefix,
      tokens-mat-protected-button.get-token-slots());
    @include button-base.mat-private-button-touch-target(false, tokens-mat-protected-button.$prefix,
      tokens-mat-protected-button.get-token-slots());

    @include token-utils.use-tokens(
      tokens-mdc-protected-button.$prefix,
      $mdc-button-protected-slots) {
      @include button-base.mat-private-button-elevation(container-elevation);

      &:hover {
        @include button-base.mat-private-button-elevation(hover-container-elevation);
      }

      &:focus {
        @include button-base.mat-private-button-elevation(focus-container-elevation);
      }

      &:active, &:focus:active {
        @include button-base.mat-private-button-elevation(pressed-container-elevation);
      }

      // We need to re-apply the disabled tokens since MDC uses
      // `:disabled` which doesn't apply to anchors.
      @include button-base.mat-private-button-disabled {
        @include token-utils.create-token-slot(color, disabled-label-text-color);
        @include token-utils.create-token-slot(background-color, disabled-container-color);

        &.mat-mdc-button-disabled {
          @include button-base.mat-private-button-elevation(disabled-container-elevation);
        }
      }
    }
  }

  .mat-mdc-outlined-button {
    $mdc-outlined-button-slots: tokens-mdc-outlined-button.get-token-slots();

    @include mdc-button-outlined-theme.theme-styles($mdc-outlined-button-slots);
    @include button-base.mat-private-button-horizontal-layout(tokens-mat-outlined-button.$prefix,
      tokens-mat-outlined-button.get-token-slots(), false);
    @include button-base.mat-private-button-ripple(tokens-mat-outlined-button.$prefix,
      tokens-mat-outlined-button.get-token-slots());
    @include button-base.mat-private-button-touch-target(false, tokens-mat-outlined-button.$prefix,
      tokens-mat-outlined-button.get-token-slots());

    @include token-utils.use-tokens(
      tokens-mdc-outlined-button.$prefix,
      $mdc-outlined-button-slots) {
      // We need to re-apply the disabled tokens since MDC uses
      // `:disabled` which doesn't apply to anchors.
      @include button-base.mat-private-button-disabled {
        @include token-utils.create-token-slot(color, disabled-label-text-color);
        @include token-utils.create-token-slot(border-color, disabled-outline-color);
      }
    }
  }
}

.mat-mdc-button-base {
  text-decoration: none;
}

.mat-mdc-button,
.mat-mdc-unelevated-button,
.mat-mdc-raised-button,
.mat-mdc-outlined-button {
  @include button-base.mat-private-button-interactive();
  @include style-private.private-animation-noop();

  // Similar to MDC's `_icon-structure`, apart from the margin which we
  // handle via custom tokens in `mat-private-button-horizontal-layout`.
  & > .mat-icon {
    $icon-size: mdc-typography.px-to-rem(18px);
    display: inline-block;
    position: relative;
    vertical-align: top;
    font-size: $icon-size;
    height: $icon-size;
    width: $icon-size;
  }
}

// Since the stroked button has has an actual border that reduces the available space for
// child elements such as the ripple container or focus overlay, an inherited border radius
// for the absolute-positioned child elements does not work properly. This is because the
// child element cannot expand to the same boundaries as the parent element with a border.
// In order to work around this issue by *not* hiding overflow, we adjust the child elements
// to fully cover the actual button element. This means that the border-radius would be correct
// then. See: https://github.com/angular/components/issues/13738
.mat-mdc-outlined-button .mat-mdc-button-ripple,
.mat-mdc-outlined-button .mdc-button__ripple {
  $offset: -(mdc-button-variables.$outlined-border-width);
  top: $offset;
  left: $offset;
  bottom: $offset;
  right: $offset;
  border-width: $offset;
}

// For the button element, default inset/offset values are necessary to ensure that
// the focus indicator is sufficiently contrastive and renders appropriately.
.mat-mdc-unelevated-button,
.mat-mdc-raised-button {
  .mat-mdc-focus-indicator::before {
    $default-border-width: focus-indicators-private.$default-border-width;
    $border-width: var(--mat-mdc-focus-indicator-border-width, #{$default-border-width});
    $offset: calc(#{$border-width} + 2px);
    margin: calc(#{$offset} * -1);
  }
}

.mat-mdc-outlined-button .mat-mdc-focus-indicator::before {
  $default-border-width: focus-indicators-private.$default-border-width;
  $border-width: var(--mat-mdc-focus-indicator-border-width, #{$default-border-width});
  $offset: calc(#{$border-width} + 3px);
  margin: calc(#{$offset} * -1);
}
